﻿#pragma warning disable IDE0057

using System.Runtime.CompilerServices;
using System.Text;

namespace Sudoku.CodeGen.KeyedTuple
{
	partial class KeyedTupleGenerator
	{
		private static partial string PrintOpenBracketToken(int indentingCount) =>
			indentingCount == 0 ? "{" : $"{new string('\t', indentingCount)}{{";

		private static partial string PrintClosedBracketToken(int indentingCount) =>
			indentingCount == 0 ? "}" : $"{new string('\t', indentingCount)}}}";

		private static partial string PrintHeader() => new StringBuilder()
			.AppendLine("//")
			.AppendLine("// <auto-generated>")
			.AppendLine("//     This file is generated by compiler, powered by source generator.")
			.AppendLine("// </auto-generated>")
			.AppendLine("//")
			.ToString();

		private static partial string PrintPragmaWarningDisableCS8509() => "#pragma warning disable 8509";

		private static partial string PrintUsingDirectives() => "using System.Runtime.CompilerServices;";

		private static partial string PrintNullableEnable() => "#nullable enable";

		private static partial string PrintNamespace() => "namespace System.Collections.Generic";

		private static partial string PrintCompilerGenerated()
		{
			const int o = 9;

			const string name = nameof(CompilerGeneratedAttribute);
			return $"{(UsingTabsAsIndentingCharacters ? "\t" : "    ")}[{name.Substring(0, name.Length - o)}]";
		}

		private static partial string PrintRecordDocComment(int length)
		{
			var sb = new StringBuilder();
			sb.Append(UsingTabsAsIndentingCharacters ? "\t" : "    ");
			sb.AppendLine("/// <summary>");
			sb.Append(UsingTabsAsIndentingCharacters ? "\t" : "    ");
			sb.AppendLine("/// Provides a tuple with a primary element, which means the tuple contains multiple items,");
			sb.Append(UsingTabsAsIndentingCharacters ? "\t" : "    ");
			sb.AppendLine("/// but the only specified item can be output as <see cref=\"string\"/> text.");
			sb.Append(UsingTabsAsIndentingCharacters ? "\t" : "    ");
			sb.AppendLine("/// </summary>");

			for (int i = 1; i <= length; i++)
			{
				sb
					.Append(UsingTabsAsIndentingCharacters ? "\t" : "    ")
					.Append("/// <typeparam name=\"T")
					.Append(i)
					.Append("\">The type of the property <see cref=\"KeyedTuple{");

				for (int j = 1; j <= length; j++)
				{
					sb.Append('T').Append(j).Append(CommaToken);
				}

				sb
					.Remove(sb.Length - CommaToken.Length, CommaToken.Length)
					.Append("}.Item")
					.Append(i)
					.AppendLine("\"/>.</typeparam>");
			}

			for (int i = 1; i <= length; i++)
			{
				sb
					.Append(UsingTabsAsIndentingCharacters ? "\t" : "    ")
					.Append("/// <param name=\"Item")
					.Append(i)
					.Append("\">The ")
					.Append(i);

				switch (i)
				{
					case 1 when i / 10 != 1: sb.Append("st"); break;
					case 2 when i / 10 != 1: sb.Append("nd"); break;
					case 3 when i / 10 != 1: sb.Append("rd"); break;
					default: sb.Append("th"); break;
				}

				sb.AppendLine(" item.</param>");
			}

			sb
				.Append(UsingTabsAsIndentingCharacters ? "\t" : "    ")
				.Append("/// <param name=\"PriorKey\">The prior key.</param>");

			return sb.ToString();
		}

		private static partial string PrintRecordStatement(int length)
		{
			var sb = new StringBuilder();
			sb.Append(UsingTabsAsIndentingCharacters ? "\t" : "    ");
			sb.Append("public sealed record KeyedTuple<");

			for (int i = 1; i <= length; i++)
			{
				sb.Append('T').Append(i).Append(CommaToken);
			}
			sb.Remove(sb.Length - CommaToken.Length, CommaToken.Length).Append(">(");
			for (int i = 1; i <= length; i++)
			{
				sb.Append('T').Append(i).Append(' ').Append("Item").Append(i).Append(CommaToken);
			}
			sb.Append("int PriorKey) : ITuple");
			return sb.ToString();
		}

		private static partial string PrintUserDefinedConstructorDocComment(int length)
		{
			var sb = new StringBuilder();
			sb.Append(UsingTabsAsIndentingCharacters ? "\t\t" : "        ");
			sb.AppendLine("/// <summary>");
			sb.Append(UsingTabsAsIndentingCharacters ? "\t\t" : "        ");
			sb.AppendLine($"/// Initializes an instance with the specified {length.ToString()} items, and the first one is the prior key.");
			sb.Append(UsingTabsAsIndentingCharacters ? "\t\t" : "        ");
			sb.AppendLine("/// </summary>");
			for (int i = 1; i <= length; i++)
			{
				sb
					.Append(UsingTabsAsIndentingCharacters ? "\t\t" : "        ")
					.Append("/// <param name=\"item")
					.Append(i)
					.Append("\">The item ")
					.Append(i)
					.AppendLine(".</param>");
			}

			sb.Remove(sb.Length - NewLine.Length, NewLine.Length);

			return sb.ToString();
		}

		private static partial string PrintUserDefinedConstructor(int length)
		{
			var sb = new StringBuilder();
			sb.Append(UsingTabsAsIndentingCharacters ? "\t\t" : "        ");
			sb.Append("public KeyedTuple(");
			for (int i = 1; i <= length; i++)
			{
				sb.Append('T').Append(i).Append(' ').Append("item").Append(i).Append(CommaToken);
			}
			sb.Remove(sb.Length - CommaToken.Length, CommaToken.Length).Append(')');
			if (length <= 4)
			{
				sb.Append(" : this(");
			}
			else
			{
				sb
					.AppendLine()
					.Append(UsingTabsAsIndentingCharacters ? "\t\t\t" : "            ")
					.Append(": this(");
			}

			for (int i = 1; i <= length; i++)
			{
				sb.Append("item").Append(i).Append(CommaToken);
			}
			sb.Append(1).Append(')');
			return sb.ToString();
		}

		private static partial string PrintInheritDoc() =>
			UsingTabsAsIndentingCharacters ? "\t\t/// <inheritdoc/>" : "        /// <inheritdoc/>";

		private static partial string PrintLength(int length) =>
			$"{(UsingTabsAsIndentingCharacters ? "\t\t" : "        ")}int ITuple.Length => {length.ToString()};";

		private static partial string PrintIndexerWithValue(int length)
		{
			var sb = new StringBuilder();
			sb.Append(UsingTabsAsIndentingCharacters ? "\t\t" : "        ");
			sb.Append("object? ITuple.this[int index] =>");
			if (length <= 4)
			{
				sb.Append(' ').Append(PrintIndexerValue(false, length));
			}
			else
			{
				sb.AppendLine().Append(PrintIndexerValue(true, length));
			}

			return sb.ToString();
		}

		private static partial string PrintIndexerValue(bool withIndent, int length)
		{
			var sb = new StringBuilder();
			if (withIndent)
			{
				sb.Append(UsingTabsAsIndentingCharacters ? "\t\t\t" : "            ");
			}
			sb.Append("index switch { ");
			for (int i = 1; i <= length; i++)
			{
				sb.Append(i).Append(" => ").Append("Item").Append(i).Append(CommaToken);
			}
			sb.Remove(sb.Length - CommaToken.Length, CommaToken.Length).Append(" };");

			return sb.ToString();
		}

		private static partial string PrintToStringWithValue() =>
			$"{(UsingTabsAsIndentingCharacters ? "\t\t" : "        ")}public override string ToString() => ((ITuple)this)[PriorKey]?.ToString() ?? string.Empty;";
	}
}
